package mbp.core;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import mbp.base.ResourceType;
import mbp.base.ServiceType;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Klasa przeznaczona do tworzenia obiektow typu Service na podstawie definicji w pliku
 * konfiguracyjnym Services.xml
 * @author Wojciech Wilanski
 *
 */
public class ServiceTypeBuilder 
{
	private File fileServices;
	private Document docServices;
	
	private Logger logger = Logger.getLogger(this.getClass());
	
	/**
	 * Konstruktor. Otwierany i parsowany plik konfiguracyjny: Services.xml.
	 * @param confPath - Sciezka do folderu z plikami konfiguracyjnymi. Jezeli sciezka jest
	 * pusta "", wyznaczana jest domyslna sciezka ../conf/ 
	 */
	public ServiceTypeBuilder(String confPath)
	{
		String xmlServices;
		if(confPath.compareTo("") == 0)
		{
			JarFolder jf = new JarFolder();
			xmlServices = jf.getJarFolder() + "conf" + File.separatorChar + "Services.xml";
		}
		else
		{
			xmlServices = confPath + "Services.xml";
		}
		fileServices = new File(xmlServices);
		
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		
		try {
			DocumentBuilder db1 = dbf.newDocumentBuilder();
			docServices = db1.parse(fileServices);
			
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			logger.error("ParserConfigurationException", e);
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			logger.error("SAXException", e);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			logger.error("IOException", e);
		}
	}
	
	/**
	 * Zwraca liste nazw uslug wystepujacych w zaladowanym pliku Services.xml
	 * @return
	 */
	public List<String> GetServiceTypeNames()
	{
		if(docServices == null)
		{
			return null;
		}
		
		List<String> sNames = new ArrayList<String>();
		
		docServices.getDocumentElement().normalize();
		
		NodeList servicesList = docServices.getElementsByTagName("service");
		
		for(int i=0; i<servicesList.getLength(); i++)
		{
			Element serviceElement = (Element)servicesList.item(i);			
			NodeList serviceTypeList = serviceElement.getElementsByTagName("type");
			
			sNames.add(serviceTypeList.item(0).getTextContent());
		}
		
		return sNames;
	}
	
	/**
	 * Tworzy i zwraca obiekt typu Service
	 * @param typeName
	 * @return
	 */
	public ServiceType GetServiceType(String typeName)
	{
		//Sprawdzenie czy zosatal odpowiednio zaladowany plik Services.xml
		if(docServices == null)
		{
			return null;
		}
		
		//Utworzenie referencji na obiekt ServiceType
		ServiceType serviceType = null;
		
		//StringBuilder sb = new StringBuilder();
		
		//Utworzenie tablic na typy zasobow zwi�zanych z tworzonym typem serwisu
		ArrayList<ResourceType> rctypein = new ArrayList<ResourceType>();
		ArrayList<ResourceType> rctypeout = new ArrayList<ResourceType>();
		
        docServices.getDocumentElement().normalize();
		
        //Pobranie wszystkich elementow service
		NodeList servicesList = docServices.getElementsByTagName("service");
		
		//Przejscie przez elementy service w celu odnalezienia serwisu
		for(int i=0; i<servicesList.getLength(); i++)
		{
			//pobranie listy tagow z elementu service i odnalezienie type
			Element serviceElement = (Element)servicesList.item(i);			
			NodeList serviceTypeList = serviceElement.getElementsByTagName("type");
			
			//Sprawdzenie czy typ sie zgadza z szukanym typem
			if( serviceTypeList.item(0).getTextContent().compareTo(typeName)==0 )
			{
				//Pobranie list in i out. Powno zawsze byc po jednej liscie
				NodeList rcIn = serviceElement.getElementsByTagName("in");
				NodeList rcOut = serviceElement.getElementsByTagName("out");
				
				Element rcInElement = (Element) rcIn.item(0);
				Element rcOutElement = (Element) rcOut.item(0);
				
				//Pobranie list resource z listy in i out
				NodeList rcInList = rcInElement.getElementsByTagName("resource");
				NodeList rcOutList = rcOutElement.getElementsByTagName("resource");
				
				//Utworzenie obiektu do tworzenia typow zasobow
				ResourceTypeBuilder rtb = new ResourceTypeBuilder("");
				
				//Przejscie przez listy in i utworzenie typow zasobow z listy in
				for(int j=0; j<rcInList.getLength(); j++)
				{
					Element rcNameIn = (Element) rcInList.item(j);
					String point = rcNameIn.getAttribute("point");
					
					//sb.append(" Resource type In : " + rcNameIn.getTextContent() + ", point: " + point + "\n");
					
					ResourceType rcTypeIn = rtb.GetResourceType(rcNameIn.getTextContent());
					
					//Wykorzystenie dodatkowego pola w obiekcie ResourceType do dodania
					//iformacji o przeznaczeniu zesobu wejsciowego: zaliczka/towar/zaplata
					rcTypeIn.setValue(point);
					
					rctypein.add(rcTypeIn);
				}
				
				//Przejscie przez list� out i utworzenie typ�w zasob�w z listy out
				for(int j=0; j<rcOutList.getLength(); j++)
				{
					Element rcNameOut = (Element) rcOutList.item(j);
					
					//sb.append(" Resource type Out: " + rcNameOut.getTextContent());
					
					ResourceType rcTypeOut = rtb.GetResourceType(rcNameOut.getTextContent());
					rctypeout.add(rcTypeOut);
				}
				
				break;
			}
		}
		
		//logger.debug("Created new ServiceType object: " + typeName + "\n" + sb.toString());
		
		serviceType = new ServiceType(typeName, rctypein, rctypeout);
		
		return serviceType;
	}

}
